package com.jason.sms.agent.protocol.cmpp3.util;

import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.codec.digest.DigestUtils;

import com.jason.sms.agent.protocol.cmpp3.msg.LoginMsg;
import com.jason.sms.agent.protocol.cmpp3.msg.LoginMsgResp;
import com.jason.sms.agent.protocol.cmpp3.msg.Msg;
import com.jason.sms.agent.protocol.cmpp3.msg.MsgCommand;

public class Utils {

	private static AtomicInteger seq = new AtomicInteger(0);

	public static int getSeq() {
		if (seq.getAndIncrement() >= Integer.MAX_VALUE) {
			return seq.getAndSet(0);
		}
		return seq.getAndIncrement();
	}

	/**
	 * 得到格式化时间 MMDDHHMMSS格式
	 * 
	 * @return: MMDDHHMMSS格式的系统时间
	 */
	public static String getMMDDHHMMSS() {
		java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(
				"MMddhhmmss");
		java.util.Date da = new java.util.Date();
		String timeStr = sdf.format(da);
		return timeStr;
	}

	/**
	 * 根据配置中的spid和密码，生成md5串
	 * 
	 * @param spid:SP企业ID
	 * @param pwd:SP密码
	 */
	public static byte[] getLoginMd5(String spid, String pwd) {
		try {
			String timeStr = getMMDDHHMMSS();
			String s = spid + "\0\0\0\0\0\0\0\0\0" + pwd + timeStr;
			byte[] data = s.getBytes();
			byte[] result = DigestUtils.md5(data);
			return result;
		} catch (Exception ef) {
			ef.printStackTrace();
		}
		return null;
	}

	/**
	 * 向流中写入指定字节长度的字符串，不足时补0
	 * 
	 * @param dous:要写入的流对象
	 * @param s:要写入的字符串
	 * @param len:写入长度,不足补0
	 */
	public static void writeString(java.io.DataOutputStream dous, String s,
			int len) throws Exception {
		byte[] data = s.getBytes();
		if (data.length > len) {
			throw new Exception("向流中写入的字符串超长！要写" + len + " 字符串是:" + s);
		}
		int srcLen = data.length;
		dous.write(data);
		while (srcLen < len) {
			dous.write('\0');
			srcLen++;
		}
	}

	/**
	 * 从流中读取指定长度的字节，转成字符串返回
	 * 
	 * @param ins:要读取的流对象
	 * @param len:要读取的字符串长度
	 * @return:读取到的字符串
	 */
	public static String readString(java.io.DataInputStream ins, int len)
			throws Exception {
		// 1.考虑，异常怎么处理？
		byte[] b = new byte[len];
		// 2.ins.read(b);
		ins.readFully(b);
		// 3.编码方式是什么？？？
		String s = new String(b);
		s = s.trim();
		return s;
	}

	/**
	 * 将一个消息对象打包为字节组
	 * 
	 * @param msg:要打包的消息对象
	 * @return:消息生成的字节数组
	 */
	public static byte[] packMsg(Msg msg) {
		int command = msg.getCommonId();
		java.io.ByteArrayOutputStream bous = new java.io.ByteArrayOutputStream();
		java.io.DataOutputStream dous = new java.io.DataOutputStream(bous);
		try {
			switch (command) {
			case MsgCommand.CMPP_CONNECT:// 打包登陆消息
				LoginMsg lm = (LoginMsg) msg;
				dous.writeInt(lm.getTotalLength());
				dous.writeInt(lm.getCommonId());
				dous.writeInt(lm.getSequenceId());
				writeString(dous, lm.getSourceAddr(), 6);
				dous.write(lm.getAuthenticatorSource());
				dous.writeByte(lm.getVersion());
				dous.writeInt(Integer.parseInt(Utils.getMMDDHHMMSS()));
				break;
			default:
				System.err.print("错误消息打包命令" + command);
			}
			dous.flush();
			return bous.toByteArray();
		} catch (Exception ef) {
			ef.printStackTrace();
		}
		return null;
	}

	/**
	 * 解包原始数据为具体的消息对象:传入的字节不含消息总长度4个字节 
	 * 
	 * @param data:去掉一个消息头长度的消息的原始字节
	 * @return :将原始数据解包成的消息对象
	 */
	public static Msg parseMsg(byte[] data) {
		try {
			// 先构造一段内存流
			java.io.ByteArrayInputStream bins = new java.io.ByteArrayInputStream(
					data);
			java.io.DataInputStream dins = new java.io.DataInputStream(bins);
			int command = dins.readInt();// 读到类型
			// 根据具体的类型来解包
			switch (command) {
			case MsgCommand.CMPP_CONNECT:// 要解包登陆消息
				LoginMsg ml = new LoginMsg();
				ml.setTotalLength(data.length + 4);
				ml.setCommonId(command);
				ml.setSequenceId(dins.readInt());
				ml.setSourceAddr(readString(dins, 6));
				byte[] ad = new byte[16];
				dins.read(ad);
				ml.setAuthenticatorSource(ad);
				ml.setVersion(dins.readByte());
				ml.setTimestamp(dins.readInt());
				return ml;
			case MsgCommand.CMPP_CONNECT_RESP:// 要解包登陆应答消息
				LoginMsgResp mlr = new LoginMsgResp();
				mlr.setTotalLength(data.length + 4);
				mlr.setCommonId(command);
				mlr.setSequenceId(dins.readInt());
				mlr.setStatus(dins.readInt());// 读取状态
				byte[] rad = new byte[16];
				dins.read(rad); // 读取认证串
				mlr.setAuthenticatorISMG(rad);
				mlr.setVersion(dins.readByte());
				return mlr;
			default:
			}
		} catch (Exception ef) {
			ef.printStackTrace();
		}

		return null;
	}

}
